Circle

2021 - Sean Baxter - circlelang@gmail.com

Follow me on Twitter, @seanbax, for compiler updates.

Download the latest version: Build 139 for 64-bit Linux.

Circle is a new C++20 compiler. It's written from scratch and designed for easy extension.

The meta context

The most radical Circle feature is the meta context, which executes C++ code at compile time. Meta expression statements are evaluated at compile time. Meta for loops are unrolled at compile time.

hello.cxx Compiler Explorer

#include <iostream>

int main() {
  @meta std::cout<< "Hello world compile time!\n";
  std::cout<< "Hello world runtime!\n";
}
$ circle hello.cxx
Hello world compile time!
$ ./hello
Hello world runtime!

Put the @meta token at the start of a statement to execute it at compile time. When the statement is inside a template, it will be executed at template instantiation.

tuple.cxx Compiler Explorer

#include <iostream>

template<typename... Ts>
struct tuple {
  // At instantiation, loop through each element in the parameter pack Ts.
  // Subscript the i'th element Ts...[i].
  // Declare a data member with name @(i): _0, _1, _2, etc.
  @meta for(int i : sizeof...(Ts))
    Ts...[i] @(i);
};

int main() {
  using MyTuple = tuple<int, char, float>;
  MyTuple my_tuple { 100, 'x', 3.14 };

  // Use Circle reflection to access the member names of a class object.
  // Use the pack slice operator ...[:] to convert an object into a pack.
  // Print each member name and value with a pack expansion.
  std::cout<< MyTuple.member_names<< ": "<< my_tuple...[:]<< "\n" ...;
}
$ circle tuple.cxx
$ ./tuple
_0: 100
_1: x
_2: 3.14

You can deploy meta control flow in any curly-brace scope: namespaces, enum-specifier, class-specifier, and function bodies. We can define a generic tuple type by looping over the template's parameter pack and depositing a data member for each element.

Major extensions

Circle extends C++ by adding many novel language features. Here are the big ones:

I've been programming C++ for 25 years. This is a compiler with the the capabilities I've always wanted.

The C++ of the future

Because Circle is so easy to extend, I've gone ahead and implemented some of the most promising WG21 proposals for the C++23 timeframe.

Taken together, these make C++ programming experience a lot nicer!

GPU targets

Circle's main target is 64-bit Linux. Because all modern non-Microsoft operating systems use the same C++ ABI, it would be easy to bring Circle to these other platforms.

But Circle supports both major GPU targets as well:

  1. Circle supports GPU compute with a single-pass flavor of CUDA.
  2. Circle supports shader programming by embedding GLSL 4.6 into C++ and emitting both SPIR-V (OpenGL and Vulkan) and DXIL (Direct3D 12) byte codes.
    • Tag functions and objects with spirv attributes to target all 12 standard shader stages.
    • Use reflection and user-defined attributes to automatically generate interfaces to guide shader development.
    • Write device-portable GPGPU code with Vulkan compute, using real pointers into physical storage buffers, a powerful feature only implemented by the Circle compiler.

Circle is a heterogeneous compiler. In one translation unit, mix x64 code, CUDA code, and shader code. No tags are required. Only a single frontend pass is performed. This is the most seamless integration of CPU and GPU code of any programming language.

Using Circle

Circle is best used locally, on any recent x86-64 Linux installation. You'll need a recent libstdc++, which should be provided by your distribution's package manager. I like libstdc++-10.2.

Download the latest version: Build 139 for 64-bit Linux.

If you're on an incompatible distribution, or a different OS altogether, try running Circle through this Dockerfile.

Circle is also hosted on Compiler Explorer, so you can use it over the web.

Basic command-line options